package com.generalbackend.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.IOUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 压缩文件
 * @author tim.xie
 * @date 2022/6/8 13:17
 */
@Slf4j
public class ZipsUtil {

    /**
     * 压缩files并保存到dest
     * 如果dest file的父目录不存在,则会创建该目录
     * @param files
     * @param dest
     */
    public static void compress(List<File> files, File dest) {
        FileOutputStream out = null;
        try {
            // 创建一个目标文件dest的输出流,如果目标文件的父文件目录不存在,那么创建
            out = FileUtils.openOutputStream(dest);
            // 将待解压的文件files压缩至dest的输出流
            compress(files, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    /**
     * 压缩files 至 output stream中
     * @param files
     * @param out
     */
    public static void compress(List<File> files, OutputStream out) {
        ZipOutputStream zipOutputStream = null;
        try {
            zipOutputStream = new ZipOutputStream(out);
            compress(files, null, zipOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(zipOutputStream);
        }
    }

    private static void compress(List<File> files, String parentDir, ZipOutputStream out) throws IOException {
        // 重复的名字进行重命名
        Map<String, Integer> names = new HashMap<>();
        for (int i = 0; i< files.size(); i++) {
            File compressed = files.get(i);
            String fileName = "";
            if (StringUtils.isNotBlank(parentDir)) {
                fileName = parentDir + compressed.getName();
            } else {
                fileName = compressed.getName();
            }
            if (compressed.isDirectory()) {
                fileName += "/";
                out.putNextEntry(new ZipEntry(fileName));
                File[] children = compressed.listFiles();
                compress(Arrays.asList(children), fileName, out);
            } else {
                // 防止重复命名
                fileName = getFileName(names, fileName);
                out.putNextEntry(new ZipEntry(fileName));
                FileUtils.copyFile(compressed, out);
            }
            out.closeEntry();
        }
    }

    private static String getFileName(Map<String, Integer> names, String fileName) {
        if (!names.containsKey(fileName)) {
            names.put(fileName, 1);
            return fileName;
        }
        Integer num = names.get(fileName);
        num++;
        names.put(fileName, num);
        fileName = "(" + num + ")" + fileName;
        fileName = getFileName(names, fileName);
        return fileName;
    }
}
